package com.smfx.yxt.filter;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.smfx.yxt.common.AdminUser;
import com.smfx.yxt.common.AppUser;
import com.smfx.yxt.common.Const;
import com.smfx.yxt.common.Constants;
import com.smfx.yxt.common.MenuConst;
import com.smfx.yxt.common.WechatConfigure;
import com.smfx.yxt.common.enums.ResourceRange;
import com.smfx.yxt.common.enums.UserRole;
import com.smfx.yxt.model.SysResource;
import com.smfx.yxt.model.TeacherInfo;
import com.smfx.yxt.reqVo.ParentReqVO;
import com.smfx.yxt.service.IParentService;
import com.smfx.yxt.service.ISysResourceService;
import com.smfx.yxt.service.ITeacherService;
import com.smfx.yxt.service.ITermInfoService;
import com.smfx.yxt.utils.BeanUtils;
import com.smfx.yxt.utils.RequestUtil;
import com.smfx.yxt.utils.StringUtil;
import com.smfx.yxt.utils.TextUtil;
import com.smfx.yxt.view.ParentRelStudentView;
import com.smfx.yxt.view.SysResourceView;
import com.smfx.yxt.view.TeacherInfoView;
import com.smfx.yxt.view.TermView;
import com.smfx.yxt.wechat.model.WechatUserInfo;
import com.smfx.yxt.wechat.utils.WechatGlobalMap;
import com.smfx.yxt.wechat.utils.WechatGlobalValue;
import com.smfx.yxt.wechat.utils.WechatUtils;

public class SessionFilter extends OncePerRequestFilter {
	
	@Override
	protected void doFilterInternal(HttpServletRequest request, 
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		// 设置request和response的字符集，防止乱码
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        // 请求的uri
        String uri = request.getRequestURI();
        uri = uri.replace(Const.PROJECT_NAME, "");
        FilterConfig config = getFilterConfig();
        
        //止后缀无需过滤，配置的资源文件
        String suffix = config.getInitParameter("suffix");
		String[] suffixList = suffix.split(";");
		if (isContains(uri, suffixList)) {
			filterChain.doFilter(request, response);
			return;
		}
		String access = config.getInitParameter("access");
		String[] accessList = access.split(";");
		if(isContains(uri, accessList)) {
			filterChain.doFilter(request, response);
			return;
		}
		
		String requestType = StringUtil.emptyToNull(request.getHeader("X-Requested-With"));
		if(requestType != null && requestType.equals("XMLHttpRequest")) {
			filterChain.doFilter(request, response);
			return;
		}
		String login = config.getInitParameter("login");
		String[] loginList = login.split(";");
		if (isContains(uri, loginList)) {
			AdminUser user = (AdminUser) request.getSession().getAttribute(Constants.ADMIN_USER);
			if(user == null) {
				request.getRequestDispatcher("/auth/login").forward(request, response);
				return;
			}
			String path = request.getContextPath();
			//根据uri获取当前菜单
        	SysResource menu = user.getSysMenuMap().get(uri.replaceAll(path, ""));
        	if(menu == null && uri.indexOf("/auth/") == -1 && uri.indexOf("/report/") == -1){
        		//如果为空，提示页面不存在
        		String respUrl = RequestUtil.getBasePath(request);
        		response.sendRedirect(respUrl+"/error/404.jsp");
        		return;
        	}
        	if(menu != null) request.setAttribute("menu", menu);
        	filterChain.doFilter(request, response);
        	return;
		}
		
		WechatUserInfo userInfo = (WechatUserInfo) request.getSession().getAttribute(Constants.WECHAT_USERINFO);
		String openid = RequestUtil.getOpenid(request);
		if(openid == null && userInfo != null) {
			openid = userInfo.getOpenid();
			RequestUtil.saveCookie(response, Const.OPENID_COOKIE, userInfo.getOpenid(), (90 * 24 * 60 * 60));
		}
		if(StringUtils.isNotBlank(openid)) {
			if(userInfo == null) {
				userInfo = WechatUtils.getUserInfo(WechatUtils.getWechatModel().getAccessToken(), openid);
				if(userInfo.getSubscribe() == 0) {
					response.sendRedirect(getRedirectUrl(uri));
					return;
				}
				request.getSession().setAttribute(Constants.WECHAT_USERINFO, userInfo);
			}
			ServletContext context = config.getServletContext();
			String noPower = config.getInitParameter("noPower");
			String noPowerWith = config.getInitParameter("noPowerWith");
			if(filterUser(request, response, context, openid, noPower, noPowerWith)) {
				filterChain.doFilter(request, response);
				return;
			}
		}else {
			response.sendRedirect(getRedirectUrl(uri));
            return;
		}
	}
	
	private static String getRedirectUrl(String requestUri) {
		WechatConfigure configure = WechatConfigure.getInstance();
		String selfUrl = Const.BASEPATH + "/common/wechatauth?self=" + requestUri;
		String url = TextUtil.format(configure.getOauth2Userinfo(), 
				new String[]{configure.getAppid(), URLEncoder.encode(selfUrl)});
		return url;
	}
	
	public static boolean isContains(String container, String[] regx) {
		boolean result = false;
		for (int i = 0; i < regx.length; i++) {
			regx[i] = regx[i].trim();
			if (container.indexOf(regx[i]) != -1) {
				result = true;
			}
		}
		return result;
	}
	
	public static boolean isEqual(String container, String[] regx) {
		boolean result = false;
		for (int i = 0; i < regx.length; i++) {
			regx[i] = regx[i].trim();
			if (container.equals(regx[i])) {
				result = true;
				break;
			}
		}
		return result;
	}
	
	public boolean filterUser(HttpServletRequest request, HttpServletResponse response,
			ServletContext context, String openid, String noPower, 
			String noPowerWith) throws ServletException, IOException{
		Boolean isOk = true;
		Integer sid = StringUtil.stringToInt(request.getParameter("sid"));
		String uri = request.getRequestURI();
		String contextPath = request.getContextPath();
		String shortUri = uri.replaceAll(contextPath, "");
		AppUser appUser = (AppUser) request.getSession().getAttribute(Constants.APP_USER);
		if(appUser != null && !uri.startsWith(contextPath + appUser.getCurrUrl())) {
			request.getSession().removeAttribute(Constants.APP_USER);
			appUser = null;
		}
		if(appUser == null) {
			ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
			IParentService parentService = (IParentService) ctx.getBean("parentService");
			ITeacherService teacherService = (ITeacherService) ctx.getBean("teacherService");
			ISysResourceService sysResourceService = (ISysResourceService) ctx.getBean("sysResourceService");
			appUser = new AppUser();
			appUser.setOpenid(openid);
			if(uri.startsWith(contextPath + Const.STUDENT_ROLE)) {
				appUser.setRoleType(UserRole.PARENT.getCode());
				appUser.setCurrUrl(Const.STUDENT_ROLE);
				ParentReqVO reqVO = new ParentReqVO();
				reqVO.setOpenid(openid);
				int count = parentService.selectStudentCountForParent(reqVO);
				if(count == 0) {
					request.getRequestDispatcher(MenuConst.STUDENT_BIND).forward(request, response);
					return false;
				}else {
					if(sid == null) {
						request.getRequestDispatcher(Const.STUDENT_ROLE + MenuConst.USER_ROLE_URL).forward(request, response);
						return false;
					}
					ParentReqVO vo = new ParentReqVO();
					vo.setOpenid(openid);
					vo.setStudentId(sid);
					List<ParentRelStudentView> parentList = parentService.selectStudentListForParent(vo);
					if(parentList.size() == 0) {
						request.getRequestDispatcher(Const.STUDENT_ROLE + MenuConst.USER_ROLE_URL).forward(request, response);
						return false;
					}
					appUser.setParent(parentList.get(0));
					TermView termView = getCurrentTerm(ctx);
					if(appUser.getParent().getGrade().intValue() <= termView.getFinishYear().intValue()
						&& !isContains(shortUri, new String[]{"/xs/student/groupup"})) {
						request.getSession().setAttribute(Constants.APP_USER, appUser);
						request.getRequestDispatcher(Const.STUDENT_ROLE + "/graduate").forward(request, response);
						return false;
					}
					SysResource queryVO = new SysResource();
					queryVO.setResourceRange(ResourceRange.PARENT.getCode());
					List<SysResource> list = sysResourceService.selectByParam(queryVO);
					List<SysResourceView> viewList = BeanUtils.copyAs(list, SysResourceView.class);
					appUser.setResourceList(viewList);
				}
			} else if(uri.startsWith(contextPath + Const.TEACHER_ROLE)) {
				appUser.setRoleType(UserRole.TEACHER.getCode());
				appUser.setCurrUrl(Const.TEACHER_ROLE);
				TeacherInfo teacher = teacherService.selectByOpenid(openid);
				if(teacher == null) {
					request.getRequestDispatcher(MenuConst.TEACHER_BIND).forward(request, response);
					return false;
				}
				TeacherInfoView teacherView = BeanUtils.copyAs(teacher, TeacherInfoView.class);
				appUser.setTeacher(teacherView);
				List<SysResource> list = sysResourceService.selectPageByIds(teacher.getPosition());
				List<SysResourceView> viewList = BeanUtils.copyAs(list, SysResourceView.class);
				appUser.setResourceList(viewList);
			}
			request.getSession().setAttribute(Constants.APP_USER, appUser);
		}else {
			String[] powerWithList = noPowerWith.split(";");
			if(isContains(shortUri, powerWithList)) {
				return isOk;
			}
			if(uri.startsWith(contextPath + Const.STUDENT_ROLE)) {
				ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
				IParentService parentService = (IParentService) ctx.getBean("parentService");
				if(sid != null) {
					if(appUser.getParent().getStudentId().intValue() == sid.intValue()) {
						TermView termView = getCurrentTerm(ctx);
						if(appUser.getParent().getGrade().intValue() <= termView.getFinishYear().intValue()
								&& !isContains(shortUri, new String[]{"/xs/student/groupup"})) {
							request.getRequestDispatcher(Const.STUDENT_ROLE + "/graduate").forward(request, response);
							return false;
						}
						return isOk;
					}else {
						ParentReqVO vo = new ParentReqVO();
						vo.setOpenid(openid);
						vo.setStudentId(sid);
						List<ParentRelStudentView> parentList = parentService.selectStudentListForParent(vo);
						if(parentList != null && parentList.size() > 0) {
							appUser.setParent(parentList.get(0));
							TermView termView = getCurrentTerm(ctx);
							if(appUser.getParent().getGrade().intValue() <= termView.getFinishYear().intValue()
									&& !isContains(shortUri, new String[]{"/xs/student/groupup"})) {
								request.getRequestDispatcher(Const.STUDENT_ROLE + "/graduate").forward(request, response);
								return false;
							}
							return isOk;
						}
					}
				}
				ParentReqVO vo = new ParentReqVO();
				vo.setOpenid(openid);
				List<ParentRelStudentView> list = parentService.selectStudentListForParent(vo);
				if(list.size() > 1) {
					request.getRequestDispatcher(Const.STUDENT_ROLE + MenuConst.USER_ROLE_URL).forward(request, response);
					return false;
				}else {
					if(list.size() == 0) {
						request.getRequestDispatcher(MenuConst.STUDENT_BIND).forward(request, response);
						return false;
					}
					appUser.setParent(list.get(0));
					request.getRequestDispatcher(Const.STUDENT_ROLE).forward(request, response);
					return false;
				}
			} else if(uri.startsWith(contextPath + Const.TEACHER_ROLE)) {
				String[] powerList = noPower.split(";");
				if (isEqual(shortUri, powerList)) {
					return isOk;
				}
				boolean isContains = false;
				
				List<SysResourceView> list = appUser.getResourceList();
				for(SysResourceView view : list) {
					if(shortUri.startsWith(Const.TEACHER_ROLE + view.getResourceUrl())){
						isContains = true;
						break;
					}
				}
				return isContains;
			}
		}
		return isOk;
	}
	
	private TermView getCurrentTerm(ApplicationContext context) {
		WechatGlobalValue value = WechatGlobalMap.get(Const.CACHE_TERM);
		if(value == null) {
			ITermInfoService termInfoService = (ITermInfoService) context.getBean("termInfoService");
			TermView view = termInfoService.selectCurrentTerm();
			view.init();
			WechatGlobalMap.put(Const.CACHE_TERM, view, 24*60*60);
			return view;
		}
		return (TermView) value.getValue();
	}
}
